/*************************
 * LR通讯协议
 * 通讯协议及全局变量
 * 2019.11.15 只保留TLR兼具通讯协议及单例
 * 2020.10.19 增加位读写函数
 * 2021.04.15 增加 辅助_MAC地址6字节转字符串
 *                 辅助_获取指定IP的MAC地址(仅WIN平台)
 *                 辅助_获取结构体偏移(因为传统的offsetof不能加入变量表达式)
 *                 LR标准协议_广播修改IP(强制)
 * 2021.05.26 增加校时结构和函数
*************************/
#ifndef TLRCOMMPROTOL_H
#define TLRCOMMPROTOL_H

#include <QObject>
#include <QNetworkInterface>
#include <QDate>
#include <QSettings>
#include <QApplication>
#include <QUdpSocket>
#include <QtConcurrent/QtConcurrentRun>
#include <QFutureWatcher>
#include <QSerialPortInfo>
#include <QSerialPort>
#include "tlrstructmodel.h"

//------------------通用数据结构-----------------------------------
typedef char s8;
typedef unsigned char u8;
typedef quint16 u16;
typedef qint16 s16;
typedef quint32 u32;
typedef qint32 s32;
typedef quint64 u64;

//UDP报文
typedef struct {
    char Cmd[10];
    char IdentifyingCode[20];
    u8 StartByte;
    u8 CmdType;
    u16 ParaStaAdd;
    u16 ParaNum;
    u8 Para[1024];
    u16 ChkSum;
}TUDPSysPara;

//UDP无数据报文
typedef struct {
    char Cmd[10];
    char IdentifyingCode[20];
    u8 StartByte;
    u8 CmdType;
    u16 ParaStaAdd;
    u16 ParaNum;
    u16 ChkSum;
}TUDPSetParaConfirm;

typedef struct {
    char MyName[64];
    char EquType[16];
    char EquSer[16];
    char FWVer[16];
    char FWDate[12];
    char OSType[4];  //OS类型 'Linx':Linux设备 'Andr':安卓设备
    u16 Address;
    u16 Baud;
    u8  mac[6];
    u8  ip[4];
    u8  maskip[4];
    u8  gatewayip[4];
    u16 UDPport;
    u16 WWWport;
    u16 TCPport;
    u16 UPGRADEport;
    char FirstUse[8];
    u32 rev;
}TAddressPara;

//UDP广播搜索报文
typedef struct {
    u16  Address;
    char Cmd[16];
    TAddressPara AddressPara;
    u16 ChkSum;
}TUDPAddressPara;

typedef struct {   //iap start,run app
    u16  Address;
    char Cmd[16];
    u16  chksum;
}TIAPSigCmd;

//FLASH指令报文
typedef struct { //erase  ,prog ack
    u16  Address;
    char Cmd[16];
    u32  StaAdd;
    u32  DatLen;
    u16  chksum;
} TFlashAddCmd;

//FLASH数据报文
typedef struct { //prog
    u16  Address;
    char Cmd[16];
    u32  StaAdd;
    u32  DatLen;
    u8   databuf[1024];
    u16  chksum;
}TFlashProg;

typedef struct
{
u16 msCnt;
u8 sec,min,hour,date,month,year;
u8 weekday;
}TSysTime;

//校时结构
typedef struct {//port 15288
char Cmd[20];  //"CalibDateTime"
TSysTime DT;
}TUDPCalibTime;

//本机IP参数
struct TMyIP{
    u8 ip[4];
    u8 netmask[4];
    u8 mac[6];
    u8 gateway[4];

    /*
     * 构造函数
     */
    TMyIP() {
        memset(ip,0x00,4);
        memset(netmask,0x00,4);
        memset(mac,0x00,6);
        memset(gateway,0x00,4);
    }

    /*
     * 是否为空
     * 返回值 : true:空 false:有IP
     */
    bool isNull() {
        bool nisnull = false;
        if(ip[0] == 0x00 && ip[1] == 0x00 &&
                ip[2] == 0x00 && ip[3] == 0x00 ) {
            nisnull = true;
        }
        return nisnull;
    }

    /*
     * 清空
     */
    void clear() {
        memset(ip,0x00,4);
        memset(netmask,0x00,4);
        memset(mac,0x00,6);
    }

    /*
     * 清空网关
     */
    void clearGateway() {
        memset(gateway,0x00,4);
    }

    /*
     * 获取IP
     * 返回值 : IP
     */
    QHostAddress getIP() {
        QHostAddress nip;
        quint32 nipint;
        u8 niptmp[4];
        niptmp[0] = ip[3];
        niptmp[1] = ip[2];
        niptmp[2] = ip[1];
        niptmp[3] = ip[0];
        memcpy(&nipint,niptmp,4);
        nip.setAddress(nipint);
        return nip;
    }
};

//================本项目数据结构==========================


//======================================================
class TLR : public QObject
{
    Q_OBJECT
public:
    explicit TLR(QObject *parent = nullptr);
    static TLR *get();

    //辅助_查询指定IP对应的网卡信息
    static QNetworkInterface getNetInfoAsnIP(QHostAddress npcip);
    //辅助_查询指定IP对应的MYIP信息
    static TMyIP getTMyIPAsnIP(QHostAddress npcip);
    //辅助_查询本机IP信息
    static QList<QHostAddress> getAllAddressIPv4();
    //辅助_4字节IP转地址
    static QHostAddress ip4toAddress(const u8 nip[4]);
    //辅助_IP地址转4字节
    static void addressToIP4(QHostAddress nipaddr,u8 nip[4]);
    //辅助_MAC字符串转6字节
    static void stringToMac6(const QString &nmacstr,u8 nmac[6],const QString &nsplit = ":");
    //辅助_MAC地址6字节转字符串
    static QString mac6ToString(const u8 nmac[6],const QString &nsplit = "-");
    //辅助_获取指定IP的MAC地址(仅WIN平台)
    static void getMacAsnIP(const QHostAddress &nip,u8 nmac[6]);
    //辅助_获取结构体偏移(因为传统的offsetof不能加入变量表达式)
    static int dynOffsetof(const void* nsta,const void* ndest);

    //LR标准协议_读取数据
    static QList<QByteArray> rdPara(QString nequidstr,int startpos, int paranum);
    //LR标准协议_读取数据(串口)
    static QList<QByteArray> rdParaSerial(QString nequidstr,int startpos, int paranum,quint16 naddr);
    //LR标准协议_下载数据
    static QList<QByteArray> wrPara(QString nequidstr,int startpos, int paranum,const void* dp);
    //LR标准协议_控制数据
    static QList<QByteArray> ctlPara(QString nequidstr,int startpos, int paranum,const void* dp);
    //LR标准协议_读取FLASH数据
    static QList<QByteArray> rdParaFlash(int address,int staadd,int datlen);
    //LR标准协议_下载FLASH数据
    static QList<QByteArray> wrParaFlash(int address,int staadd,int datlen,const void *pdata);
    //LR标准协议_合成数据
    static QList<QByteArray> makePara(QString nequidstr,int startpos, int paranum,int ncmdtype,const QByteArray &ncmd);
    //LR标准协议_FLASH指令报文
    static QByteArray packFlashAddCmd(int address,int staadd,int datlen,QByteArray ncmdbyte);
    //LR标准协议_搜索在线设备
    static QByteArray searchEqu();
    //LR标准协议_广播修改IP(强制)
    static QByteArray bcastSetIP(char uid[14],u8 nmac[6],u8 nip[4]);
    //LR标准协议_校时
    static QByteArray calibTime();
    //LR标准协议_IAP指令
    static QByteArray packIapSigCmd(const QByteArray &ncmd);

    /*
     * 位读
     * nvar    : 原始值
     * nbitidx : 位序号
     * 返回值   : 位值
     */
    template<typename T>
    static bool bitGet(T nvar, int nbitidx)
    {
        bool nbitval = false;
        if((nvar >> nbitidx) & 0x01) {
            nbitval = true;
        }
        return nbitval;
    }
    /*
     * 位操作
     * nvar    : 原始值
     * nbitidx : 位序号
     * nbitval : 位值
     * 返回值   : 修改后的值
     */
    template<typename T>
    static T bitSet(T nvar, int nbitidx, bool nbitval)
    {
        T nvarsetted;
        if(nbitidx >=0 && nbitidx <= 63) {
            u64 nbitmask = 0x00000001;
            nbitmask = nbitmask << nbitidx;
            if(nbitval) {
                nvar |= nbitmask;
            }
            else {
                nvar &= ~nbitmask;
            }
        }
        nvarsetted = nvar;
        return nvarsetted;
    }
    //辅助_延时非阻塞
    static void delayMs(int nmsec);

    //发送UDP数据
    void udpSockAnyWrite(const QByteArray &nsndbyte,const QHostAddress &nip,int nport = 2305);
    void udpSockAnyWrite(const QList<QByteArray> &nsndbytes,const QHostAddress &nip,int nport = 2305);
    //设置/读取本机IP
    void setMyIP(const QHostAddress &nip);
    TMyIP getMyIP();
    //打开/关闭串口
    bool openSerialPort(const QString &nportname,qint32 nbaud);
    void closeSerialPort();
    //获取当前使用的串口
    QString getCurrentPortName();
    //串口发送数据(不可重入)
    void serialPortWrite(const QByteArray &nsndbyte,int nreadsize);
    void serialPortWrite(const QList<QByteArray> &nsndbytes,const QList<int> nreadsizes);

    //结构体解析工具
    TLRStructModel m_lrStructModel;

private:
    //UDP Socket
    QUdpSocket* m_udpSockAny = new QUdpSocket(this);
    //本机IP
    TMyIP m_myIP;
    //串口
    QSerialPort m_commUart;
    //串口发送数据锁
    bool m_serialPortLock = false;

    //数据分配给结构体
    void dataToStruct(const QByteArray &nreadbyte);

private slots:
    //收到UDP数据
    void slotUdpSockAnyReadyRead();

signals:
    //结构体数据更新
    void sigStructDataUpdate();
    //提示消息
    void sigToolTip(const QString &ntooltip);

};

#endif // TLRCOMMPROTOL_H
